package com.vpen.nexus.utils;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.store.FSDirectory;
import org.apache.maven.index.ArtifactInfo;
import org.apache.maven.index.DefaultIndexer;
import org.apache.maven.index.DefaultIndexerEngine;
import org.apache.maven.index.DefaultQueryCreator;
import org.apache.maven.index.DefaultSearchEngine;
import org.apache.maven.index.Field;
import org.apache.maven.index.FlatSearchRequest;
import org.apache.maven.index.FlatSearchResponse;
import org.apache.maven.index.Indexer;
import org.apache.maven.index.IndexerEngine;
import org.apache.maven.index.MAVEN;
import org.apache.maven.index.SearchEngine;
import org.apache.maven.index.context.IndexCreator;
import org.apache.maven.index.context.IndexingContext;
import org.apache.maven.index.creator.JarFileContentsIndexCreator;
import org.apache.maven.index.creator.MinimalArtifactInfoIndexCreator;
import org.apache.maven.index.expr.UserInputSearchExpression;
import org.apache.maven.index.updater.DefaultIndexUpdater;

/**
 * @author vpen Created on 2025/10/15 10:02
 */
@Slf4j
public class MavenUtil {


    /**
     * 获取索引环境
     */
    public static IndexingContext getIndexingContext(String outputFolderPath, String indexDirPath) {
        File outputFolder = new File(outputFolderPath);
        File indexDir = new File(indexDirPath);

        List<IndexCreator> indexers = Arrays.asList(new MinimalArtifactInfoIndexCreator(), new JarFileContentsIndexCreator());

        SearchEngine searchEngine = new DefaultSearchEngine();
        IndexerEngine indexerEngine = new DefaultIndexerEngine();
        DefaultQueryCreator queryCreator = new DefaultQueryCreator();
        Indexer indexer = new DefaultIndexer(searchEngine, indexerEngine, queryCreator);

        try {
            return indexer.createIndexingContext(
                    "central-context",        // id
                    "central-repo",            // repoId
                    outputFolder,              // repository 目录（可空目录）
                    indexDir,                 // Lucene 索引存放目录
                    null,                     // repositoryUrl
                    null,                     // indexUpdateUrl
                    true,                     // searchable
                    true,                     // reclaim
                    indexers                  // index creators
            );
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 解压索引文件
     */
    public static void unGzipIndex(String indexArchivePath, String outputFolderPath, String indexDirPath) {
        IndexingContext context = getIndexingContext(outputFolderPath, indexDirPath + "." + LocalDateTime.now().toEpochSecond(ZoneOffset.UTC));
        // 解压
        try (BufferedInputStream is = new BufferedInputStream(new FileInputStream(indexArchivePath));
             FSDirectory directory = FSDirectory.open(new File(indexDirPath).toPath())
        ) {
            DefaultIndexUpdater.unpackIndexData(is, 1, directory, context);
            getDocCount(getIndexingContext(outputFolderPath, indexDirPath));
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                context.close(true);
            } catch (IOException e) {
                log.warn("close indexing context error", e);
            }
        }
    }

    public static int getDocCount(IndexingContext context) {
        try {
            IndexSearcher indexSearcher = context.acquireIndexSearcher();
            int numDocs = indexSearcher.getIndexReader().numDocs();
            log.info("Lucene 文档数：{}", numDocs);
            return numDocs;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static Set<ArtifactInfo> searchArtifactInfo(IndexingContext context, Field field, String searchTerm) {
        Indexer indexer = getIndexer();
        // 构建搜索查询
        Query query = indexer.constructQuery(field, new UserInputSearchExpression(searchTerm));
        try (FlatSearchResponse response = indexer.searchFlat(new FlatSearchRequest(query, context))) {
            log.info("searchArtifactInfo搜索结果数量: {}", response.getTotalHitsCount());
            return response.getResults();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    public static Set<ArtifactInfo> searchAllArtifacts(IndexingContext context) {
        Indexer indexer = getIndexer();
        Query query = new MatchAllDocsQuery();
        try (FlatSearchResponse response = indexer.searchFlat(new FlatSearchRequest(query, context))) {
            log.info("searchAllArtifacts搜索结果数量: {}", response.getTotalHitsCount());
            return response.getResults();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static  Indexer getIndexer(){
        return new DefaultIndexer(new DefaultSearchEngine(), new DefaultIndexerEngine(), new DefaultQueryCreator());
    }

    public static void main(String[] args) throws IOException {
//        unGzipIndex("nexus-maven-repository-index.gz", "target/repository", "target/nexus-index");
//        int docCount = getDocCount(getIndexingContext("target/repository", "target/nexus-index"));
//        Set<ArtifactInfo> artifactInfos = searchArtifactInfo(getIndexingContext("target/repository", "target/nexus-index"),
//                MAVEN.GROUP_ID, "*");

        IndexingContext context = getIndexingContext("target/repository", "target/nexus-index");
        Set<ArtifactInfo> artifactInfos = searchAllArtifacts(context);
        for (ArtifactInfo artifactInfo : artifactInfos) {
            log.info("{}:{}:{}", artifactInfo.getGroupId(), artifactInfo.getArtifactId(), artifactInfo.getVersion());
        }
    }

}
